package com.ztrue.framework.context;

import com.ztrue.framework.core.command.EventCommittingContext;
import com.ztrue.framework.core.domain.IAggregateRootCache;
import com.ztrue.framework.core.event.IDomainEvent;
import com.ztrue.framework.core.event.IDomainEventHandler;
import com.ztrue.framework.core.event.IEventService;
import com.ztrue.framework.core.event.IEventStore;
import com.ztrue.framework.handler.IHandlerDefinitionRegistry;
import com.ztrue.framework.handler.IHandlerRegistry;

/**
 * 表示一个默认领域事件服务
 *
 * @author zhangw
 * @date 2016/12/1 17:09
 */
public class DefaultEventService implements IEventService {
    /**
     * 领域事件存储
     */
    private IEventStore eventStore;
    /**
     * 聚合根缓存
     */
    private IAggregateRootCache aggregateRootCache;
    /**
     * 处理器注册机
     */
    private final IHandlerRegistry handlerRegistry;
    /**
     * 处理器定义注册机
     */
    private final IHandlerDefinitionRegistry handlerDefinitionRegistry;

    /**
     * 初始化领域事件服务
     *
     * @param handlerRegistry           处理器注册机
     * @param handlerDefinitionRegistry 处理器定义注册机
     * @param eventStore                事件存储
     * @param aggregateRootCache        聚合根缓存
     */
    public DefaultEventService(IHandlerRegistry handlerRegistry, IHandlerDefinitionRegistry handlerDefinitionRegistry, IEventStore eventStore, IAggregateRootCache aggregateRootCache) {
        this.eventStore = eventStore;
        this.aggregateRootCache = aggregateRootCache;
        this.handlerRegistry = handlerRegistry;
        this.handlerDefinitionRegistry = handlerDefinitionRegistry;
    }

    /**
     * 提交领域事件
     *
     * @param eventCommittingContext 领域事件提交上下文
     */
    @Override
    public void commitEvent(EventCommittingContext eventCommittingContext) {
        eventStore.append(eventCommittingContext.getEventStream());
        eventCommittingContext.getAggregateRoot().acceptChanges(eventCommittingContext.getEventStream().getVersion());
        aggregateRootCache.set(eventCommittingContext.getAggregateRoot());

        //// TODO: 在此进行领域事件推送
        int l = 0;
        for (IDomainEvent domainEvent : eventCommittingContext.getEventStream().getDomainEvents()) {
            String[] handlerNames = handlerDefinitionRegistry.getHandlerNameByTargetTypeAndHandlerType(domainEvent.getClass(), IDomainEventHandler.class);
            l = handlerNames.length;
            for (int i = 0; i < l; i++) {
                builtInHandler(handlerNames[i], domainEvent, eventCommittingContext);
            }
        }
    }

    /**
     * 领域事件内部处理
     *
     * @param handlerName
     * @param domainEvent
     * @param eventCommittingContext
     */
    private void builtInHandler(String handlerName, IDomainEvent domainEvent, EventCommittingContext eventCommittingContext) {
        IDomainEventHandler eventHandler = handlerRegistry.getHandler(handlerName, IDomainEventHandler.class);
        eventHandler.handle(eventCommittingContext, domainEvent);
    }
}
